import React from 'react';
import { render } from 'react-dom';
import { connect } from 'react-redux';
import { Component } from 'react';
import { is } from 'immutable';
import * as css from './style';
import * as action from '../../../redux/action';
import { fetch, qiniu, isMobile, handleError, dom } from '../../../utils/utils';

class BookPanel extends Component {

    componentDidUpdate() {
    		let BOOK = this.props.BOOK.get('render');
    		
        if(BOOK.get('nowpage') === 1){
		        // 清空所有子节点
        		dom('div[data-type="booklist"]').innerHTML = '';
        		
        		this.createContent();
        		this.loadBooks(1, true);
        		
        		this.refs.books.scrollIntoView();
        		
        		if(BOOK.get('allpage') === 1)
        			this.changeLoadingState(true, false, '没有更多搜索结果啦~');
       	}
    }

    shouldComponentUpdate(nextProps) {
        return !is(nextProps.BOOK, this.props.BOOK) || !is(nextProps.UserIsSpread, this.props.UserIsSpread)
        				|| !is(nextProps.TABLE.toJS().isShow, this.props.TABLE.toJS().isShow);
    }
    
    scrollHeightChangeEvent(){
			let refs = this.refs,
    			panelOffset = refs.b.scrollTop,
    			scroll = this.props.SCROLL.toJS(),
    			hasChanged = scroll.showHeader,
    			top = scroll.searchHeight,
    			allbooks = this.props.BOOK.get('render').get('all');
    	
    	
    	// 如果还未搜索书籍，则不做操作。
    	if(typeof allbooks !== 'number' || allbooks <= 0)		return;
    	
    	// 滚动到第一本书位置后显示头部搜索框
    	if(!hasChanged && panelOffset >= top){
    		this.props.showHeader();
    		this.props.setShowState(true);
    	}else if(hasChanged && panelOffset < top){
    		this.props.hideHeader();
    		this.props.setShowState(false);
    	}
    	
    	let windowHeight = window.innerHeight,
    			turntop = refs.top,
    			scrollAuto = function(){
		    			turntop.style.top = panelOffset + windowHeight - 120 + 'px';
			    		turntop.setAttribute('data-isshow', 'true');
    			};
    	
    	// 滚动到足够位置后置顶按钮出现。
    	if(panelOffset > 1.5*windowHeight){
    		if(requestAnimationFrame){
    			requestAnimationFrame(scrollAuto);
    		}else{
    			scrollAuto();
    		}
    	}
    	
    	let offset = scroll.offset;
    	
    	// 滚动到足够位置后自动加载下一页的书。
    	if(panelOffset >= offset){
    		this.props.changeOffset( offset + scroll.height );
    		this.changeLoadingState(true, true, '正在努力加载中……');
    		
    		let page = this.createContent();
        fetch({
            do: 'search',
            keyword: this.props.BOOK.get('render').get('keywords'),
            page: page
        }).done(res => {
        		let isLastPage = (res.allpage === res.nowpage);
        		
        		if(isLastPage) {
							this.changeLoadingState(true, false, '没有更多搜索结果啦~');
	       			return;
	       		}
        		
        		this.changeLoadingState(false, false);
        		this.props.getBookByNextPage(res);
        		this.loadBooks(page);
        }).fail(() => {
        		handleError.bind(this)
        		this.turnTop();
        });
    	}
    }
    
    loadBooks(page, shouldinit) {
				render(
				    <Books BOOK={ this.props.BOOK }
				    			showAside={ this.props.showAside }
                  UserIsSpread={this.props.UserIsSpread}
                  spreadUserPanel={this.props.spreadUserPanel}
                  changeheight={this.props.changeHeight}
                  changeoffset={this.props.changeOffset}
                  setSearchHeight={this.props.setSearchHeight}
                  shouldinit={ shouldinit } />
				    , dom('div[data-page="' + page + '"]')
				)
    }
    
    createContent() {
    	let books = this.refs.books,
					page = books.children.length + 1,
					newNode = document.createElement('div');
			
			newNode.setAttribute('data-page', page);
			books.appendChild(newNode);
			
			return page;
    }
    
    changeLoadingState(isshow, isrota, text) {
    		let tip = this.refs.t;
    		
    		if(isshow) tip.className = `${ css.loadingTip }`;
    		tip.setAttribute('data-isshow', isshow ? 'true' : 'false');
    		tip.children[0].className = isrota ? `${ css.iconloading } ${css.loading}` : `${ css.iconloading }`;
    		tip.children[1].innerText = text ? text : '';
    }
    
    turnTop() {
    	this.refs.b.scrollTop = 0;
    }
  	
    render() {
    		let MESSAGE = this.props.MESSAGE.toJS();
    
        return (
            <div className={ css.panel } onScroll={ this.scrollHeightChangeEvent.bind(this) } ref="b" data-type="bookwrapper">
                <Search getsearch={ this.props.getBookByKeyword }
                    clearsearch={ this.props.clearAllBook }
                    sendMessage={ this.props.sendMessage }
                    defaultKeyword={ this.props.keyword }
                    hidebox={ this.props.hideBox } />
                <LibraryInfo TABLE={ this.props.TABLE.toJS() }
                		hidetable={ this.props.hideTable }
                		showtable={ this.props.showTable }/>
                
								<div data-isshow={ MESSAGE.isShow } ref="r" className={ css.searchtip }>
									{ this.props.MESSAGE.toJS().text }
								</div>
								
                <div ref="books" data-type="booklist"></div>
                
                <div className={ css.loadingTip } ref="t" data-type="loadingTip" data-isshow="false">
                	<i className={ css.iconloading }></i>
                	<span>正在努力加载中……</span>
                </div>
                
                <div className={ css.turntop } ref="top" data-isshow="false" onClick={ this.turnTop.bind(this) }>⇧</div>
            </div>
        )
    }
}

/**
 *  book search input.
 *  @props getsearch: redux action getBookByKeyword
 *  @props clearsearch: redux action clearAllBook
 *  @props sendMessage: redux action sendMessage
 *  @props hidebox: redux action hideBox
 *  @props hidetable: redux action hideTable
 *  @props defaultKeyword: string or undefined
 */
class Search extends Component{

	  constructor(props) {
        super(props);
        this.handleInput = this.handleInput.bind(this);
    }
    
    componentDidMount() {
        // 提醒用户闭关时间
        this.remindUserTime();
    }

    componentDidUpdate() {
        // 如果有defaultKeyword传入，则直接搜索它，用于页面加载时
        // 需要直接显示某个关键字的结果
        if (this.props.defaultKeyword)
            this.refs.input.value = this.props.defaultKeyword;
    }

    handleInput() {

        // 删除关键字首尾空格
        let key = this.refs.input.value.trim();
				
        if (!key || key === this.props.defaultKeyword) return false;

        // 若运行到此，则本次关键字成为上次关键字
        // 同时取消上次请求（若尚未返回数据）
        this.lastKeyword = key;
        this.lastReq && this.lastReq.abort();
        
        if (key.length === 0) {
            this.props.clearsearch();
            return false;
        }

				// IE >=10 does not support multiple parameters.
        // so use className write class name string.
        this.refs.l.className = `${ css.iconloading } ${css.loading}`;
        
        // search request
        this.lastReq = fetch({
            do: 'search',
            keyword: key,
            page: 1
        }).done(res => {
       		  let hasResult = (res.all > 0),
       		  		icon = dom('div[data-type="loadingTip"]');
       		  
        		dom('div[data-type="libinfo"]').setAttribute('data-isshow', 'false');
        		icon.className = `${ css.iconloading }`;
        		icon.setAttribute('data-isshow', 'false');
        		
        		if(!hasResult){
        			this.props.sendMessage(`找不到与 ${res.keywords} 有关的书，请尝试其他关键词。`);
        		}else{
        			this.props.hidebox();
        		}
        			
            this.props.getsearch(res);
            this.refs.l.className = `${ css.iconloading }`;
        }).fail(handleError.bind(this))
            .always(() => {
                this.refs.l.className = 'icon-loading';
            });
    }
    
    remindUserTime() {
    	var today = new Date();
    	var tip = this.refs.tip;
    	var hour = today.getHours();
    	var minute = today.getMinutes();
    	
    	// 20:30~23:59与00:00~07:59时间段提醒用户开闭馆时间
    	var isSpecialTime = (hour === 20 && minute >= 30);
    	if(hour >= 21 || isSpecialTime || (hour >= 0 && hour < 8)){
    		tip.innerHTML = isSpecialTime ? ' 书库已开放，<span>（闭关时间：21:30）</span>' :
		    																' <span>已闭馆，（开馆时间：08:00）</span> ';
    	}
    }
    
    render(){
        return (
            <div className={ css.search } data-type="search">
							<span>图书查询</span>
							<input type="text" placeholder="输入关键字开始查询" ref="input" />
              <i className={ css.iconloading } ref="l"></i>
							<button type="button" onClick={ this.handleInput } onTouchStart={ this.handleInput }>查 询</button>
							<p ref="tip"> 书库已开放</p>
						</div>
        )
    }
}

/**
 *	LibraryInfo
 *  @props TABLE: state
 *  @props showtable: redux action
 *  @props hidetable: redux action
*/
class LibraryInfo extends Component{

		showTable(){
			let isShow = ('true' === this.props.TABLE.isShow);
			
			if(isShow){
				this.refs.s.innerText = '开馆时间 ⇲';
				this.props.hidetable();
			}else{
				this.refs.s.innerText = '开馆时间 ⇱';
				this.props.showtable();
			}
		}
		
    render(){
        return (
            <div className={ css.libinfo } data-type="libinfo" data-isshow="true">
        				<span className={ css.showtable } ref="s" onClick={ this.showTable.bind(this) }>开馆时间 ⇲</span>
        				
        				<div className={ css.table } ref="tab" data-isshow={ this.props.TABLE.isShow }>
	                <div>
	                    <table>
	                        <thead>
	                            <tr>
	                                <th>库室名称</th>
	                                <th>开放时间</th>
	                            </tr>
	                        </thead>
	                        <tbody>
	                            <tr data-combind="true">
	                                <td>通信计算机书库</td>
	                                <td rowSpan="5">
	                                    <span>
	                                        周一至周五：08:00～12:00　13:30～21:30<br/>
	                                        周六至周日：14:00～21:30
	                                    </span>
	                                </td>
	                            </tr>
	                            <tr data-combind="true">
	                                <td>数理书库</td>
	                            </tr>
	                            <tr data-combind="true">
	                                <td>文艺书库</td>
	                            </tr>
	                            <tr data-combind="true">
	                                <td>社科书库</td>
	                            </tr>
	                            <tr>
	                                <td>外文书库</td>
	                            </tr>
	
	                            <tr>
	                                <td>还书处</td>
	                                <td>
	                                    <span>
	                                        周一至周五：08:00～18:00<br/>
	                                        周六至周日：14:00～17:30
	                                    </span>
	                                </td>
	                            </tr>
	                        </tbody>
	                    </table>
	                </div>
        				</div>
            </div>
        )
    }
}

/**
 *  books
 *	@props BOOK: Map
 *	@props showAside: redux action
 *  @props UserIsSpread: bool
 *  @props spreadUserPanel: redux action
 *  @props changeheight: redux action
 *  @props changeoffset: redux action
 *  @props setSearchHeight: redux action
 *  @props shouldinit: boolean
 */
class Books extends Component {

		componentDidMount() {
				// 在第一页书加载完毕后，确定offset
				if(this.props.shouldinit === true){
					let height = dom('div[data-type="book"]') ? parseInt(window.getComputedStyle(dom('div[data-type="book"]'), null).height)*20 + 190 : 0,
							searchheight = parseInt(window.getComputedStyle(dom('div[data-type="search"]'), null).height),
		    			offset = height + searchheight - 650;
		    	
		    	this.props.changeheight(height);
					this.props.changeoffset(offset);
					this.props.setSearchHeight(searchheight);
				}
		}
    
    render() {
    		let BOOK = this.props.BOOK.get('render');
        return (
	         <div>
                {
                    BOOK.get('books').map((e, i) =>
                        <Book key={i} { ...e.toObject() }
                            showAside={ this.props.showAside }
                            UserIsSpread={this.props.UserIsSpread}
                            spreadUserPanel={this.props.spreadUserPanel}/>
                    )
                }
	         </div>
        )
    }
}

/**
 *  books
 *  @props object , state.render.books[i]
 *  @props showAside, redux acton
 *  @props UserIsSpread, redux acton
 *  @props spreadUserPanel, redux acton
 */
class Book extends Component {
    render() {
        let { isbn, showAside, ...detail } = this.props;
        return (
            <div className={ css.book } data-type="book">
                <Image isbn={ isbn } />
                <Detail { ...detail } />
                <More info={ this.props }
                    showAside={ showAside }
                    UserIsSpread={ this.props.UserIsSpread }
                    spreadUserPanel={this.props.spreadUserPanel}/>
            </div>
        )
    }
}


/**
 *  book image
 *  @props isbn: string
 */
class Image extends Component {
    render() {
        let isbn = this.props.isbn;
        return (
            <div className={ css.image }>
                <img src={ `${qiniu}/${isbn}` }/>
            </div>
        )
    }
}


/**
 *  book detail
 *  @props ... , detail data
 */
class Detail extends Component {
    render() {
        let detail = this.props;
        return (
            <div className={ css.bookbase }>
                <p title={ detail.title }>{ detail.title }</p>
                <small>{ detail.author}</small>
                <small>{ detail.year }</small>
                <small>{ detail.press }</small>
            </div>
        )
    }
}


/**
 *  get more info
 *  @props info: parent props
 *  @props showAside: redux action
 *  @props UserIsSpread: bool
 *  @props spreadUserPanel: redux action
 */
class More extends Component {

    constructor(props) {
        super(props);
        this.getMore = this.getMore.bind(this);
        this.move = this.move.bind(this);
        this.end = this.end.bind(this);
    }

    getMore() {
        if (!(isMobile && this.props.UserIsSpread)) {
            this.props.showAside(this.props.info);
        }
    }

    move() {
        this.havemove = true;
    }

    end(e) {
        if (this.havemove === true) {
            e.preventDefault();
        } else {
            if (isMobile && this.props.UserIsSpread) {
                this.props.spreadUserPanel();
                e.preventDefault();
                return false;
            } else {
                this.props.showAside(this.props.info);
            }
        }
        this.havemove = false;
    }
    render() {
        return (
            <div className={ css.more }>
                <button onClick={ this.getMore }
                    onTouchEnd={ this.end }
                    onTouchMove={ this.move }
                    data-type="morebtn">详细信息</button>
            </div>
        )
    }
}

export default connect(state => ({
    BOOK: state.BOOK,
    MESSAGE: state.MESSAGE,
    SCROLL: state.SCROLL,
    TABLE: state.TABLE,
    UserIsSpread: state.USER.getIn(['unrender', 'isSpread']),
    keyword: state.BOOK.getIn(['unrender', 'keyword'])
}), action)(BookPanel);